﻿using System;
using System.IO;

namespace Microsoft.WowAddonStudio.Project.Import
{
	/// <summary>
	/// Copies an addon item from its source location to the target
	/// location.
	/// </summary>
	public class AddonItemCopier
	{
		private const int COPY_BUFFER_SIZE = 65536;

		/// <summary>
		/// Executes copying of an addon item.
		/// </summary>
		/// <param name="targetPath">Absolute target path under which addon items will be copied.</param>
		/// <param name="itemToCopy">An addon item to be copied under targetPath completed with its relative path.</param>
		/// <returns></returns>
		public static string CopyAddonItem(string targetPath, IAddonItem itemToCopy)
		{
			if (string.IsNullOrEmpty(targetPath))
				throw new ArgumentNullException("targetPath", "Target path is not specified.");

			if (null == itemToCopy)
				throw new ArgumentNullException("itemToCopy", "No item specified to copy.");

			if (targetPath.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
				throw new ArgumentException("Target path is not a valid folder name.");

			if (!Path.IsPathRooted(targetPath))
				throw new ArgumentException("Target path must be an absolute path.", "targetPath");

			//Create target directory
			DirectoryInfo targetDirectory = CreateTargetDirectory(targetPath, itemToCopy.RelativePath);
			string targetItemPath = Path.Combine(targetDirectory.FullName, Path.GetFileName(itemToCopy.RelativePath));

			using (FileStream targetFileStream = File.Open(targetItemPath, FileMode.Create, FileAccess.Write))
			{
				using (Stream addonItemStream = itemToCopy.GetStream())
				{
					CopyStream(addonItemStream, targetFileStream);
					targetFileStream.Flush();
				}
			}

			return targetItemPath;
		}

		/// <summary>
		/// Creates the target directory.
		/// </summary>
		/// <param name="targetPath">The target path.</param>
		/// <param name="relativePath">The relative path.</param>
		/// <returns></returns>
		private static DirectoryInfo CreateTargetDirectory(string targetPath, string relativePath)
		{
			string absoluteTargetPath = Path.Combine(targetPath, relativePath);
			string directoryName = Path.GetDirectoryName(absoluteTargetPath);

			DirectoryInfo result;

			if (!Directory.Exists(directoryName))
			{
				result = Directory.CreateDirectory(directoryName);
			}
			else
			{
				result = new DirectoryInfo(directoryName);
			}

			return result;
		}

		/// <summary>
		/// Copies the stream.
		/// </summary>
		/// <param name="source">The source.</param>
		/// <param name="dest">The dest.</param>
		private static void CopyStream(Stream source, Stream dest)
		{
			var buffer = new byte[COPY_BUFFER_SIZE];
			int read;

			do
			{
				read = source.Read(buffer, 0, buffer.Length);
				dest.Write(buffer, 0, read);
			} while (read != 0);
		}
	}
}